import java.awt.*;
import java.awt.event.*;
import java.awt.FileDialog;
import java.awt.FlowLayout;

import java.io.File;
import java.io.IOException;

//import javax.imageio.ImageIO;
import javax.sound.sampled.*;

import javax.swing.*;
import javax.swing.event.*;

class Option{final static int PLAY=0,PAUSE=1,STOP=2,CIRCLE=3,OPEN=4,LIST=5;}

public class MediaPlayer implements ActionListener{
    JFrame f;
    JPanel p,p_front;
    JLabel l_front;
    Image image;
    JButton buttonPlay, buttonPause, buttonStop, buttonCircle, buttonOpen, buttonPL;
    JSlider sldTime, sldVolume;
    PlayList list;
    FileDialog flg;
    AudioInputStream audioInputStream;
    AudioFormat audioFormat;
    Clip myClip;
    File file;
    final String strCmd[]={"buttonPlay","buttonPause","buttonStop","buttonCircle","buttonOpen","buttonPL"};
    int pathNum = 0, pathCurrent=-1;
    String[] filePath = {"","","","","","","","","","","","","","","",""}; 
    Thread myThread;
    boolean myClipSwith = false;
    double fileLength=0.0, lengthPerSecond=0.0;
    int totalSeconds=0, soundMinutes=0, soundSeconds=0;	//time length of the file
    int playMinutes=0, playSeconds=0, playTotalSecs=0;	//time progress of the player
    FloatControl gainControl;		//volume control
    
	Icon play_normal = new ImageIcon("Button/b_play_01.png");
	Icon stop_normal = new ImageIcon("Button/b_stop_01.png");
	Icon suspend_normal = new ImageIcon("Button/b_suspend_01.png");
	Icon next_normal = new ImageIcon("Button/b_next_01.png");
	Icon back_normal = new ImageIcon("Button/b_back_01.png");	
    Icon loopon_normal = new ImageIcon("Button/loopon_push.png");
    Icon loopoff_normal = new ImageIcon("Button/loopoff_normal.png");
    Icon open_normal = new ImageIcon("Button/b_seek_01.png");
    Icon play_list = new ImageIcon("Button/b_PL_01.png");

    
    public  void AudioLoad()
    {
        filePath[pathCurrent] = flg.getDirectory()+flg.getFile();
        //f.setTitle(title));
        audioInputStream = null;
        file = null;
        audioFormat = null;
        file = new File(filePath[pathCurrent]);
        try {
            audioInputStream = AudioSystem.getAudioInputStream(file);
            

        } catch (UnsupportedAudioFileException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        audioFormat = audioInputStream.getFormat();
    }
    
    public void myClipLoad(){
        if (myClip != null){
            //myClip.close();
        }
        else{
          //get time length of the file(in "M:S" format)
	        fileLength = audioInputStream.getFrameLength();
	        lengthPerSecond = audioInputStream.getFormat().getSampleRate();
	        totalSeconds = (int) (fileLength/lengthPerSecond);
	        soundMinutes = totalSeconds/60;
	        soundSeconds = totalSeconds%60;
	        
          //get the progress of the player (playTotalSecs : in the foramt of seconds; playMinutes and playSeconds means "M:S")
			    playTotalSecs = (int) (sldTime.getValue()/ audioInputStream.getFormat().getSampleRate());
	        playMinutes = playTotalSecs/60;
	        playSeconds = playTotalSecs%60;
	        
	        sldTime.setBorder(BorderFactory.createTitledBorder(playMinutes+":"+playSeconds+" / "+soundMinutes+":"+soundSeconds));
	        DataLine.Info info = new DataLine.Info(Clip.class, audioFormat);
	        try {
	            myClip  = (Clip) AudioSystem.getLine(info);
	            myClip.open(audioInputStream);
	            
	            //gain the control of volume
	            gainControl = (FloatControl) myClip.getControl(FloatControl.Type.MASTER_GAIN);
	        } catch (LineUnavailableException e2) {
	            // TODO Auto-generated catch block
	            e2.printStackTrace();
	        } catch (IOException e2) {
	            // TODO Auto-generated catch block
	            e2.printStackTrace();
	        }
        }
        
    }
     
    public MediaPlayer()
    {
    	//the setting of time info
        	
    	sldTime = new JSlider(0,100,0);
    	sldTime.setBorder(BorderFactory.createTitledBorder("0:0 / 0:0"));
    	sldTime.addChangeListener(new ChangeListener(){
    	    public void stateChanged(ChangeEvent e)
    	    {
    	        if ( ((JSlider)e.getSource() == sldTime) && (myClip != null)){
    	        	if((myClip.getFramePosition() > sldTime.getValue()+audioFormat.getSampleRate()) || myClip.getFramePosition() < sldTime.getValue()){
    	        		myClip.setFramePosition(sldTime.getValue());
    	        		
    	        		//get the progress of the player (playTotalSecs : in the foramt of seconds; playMinutes and playSeconds means "M:S")
    	        		playTotalSecs = (int) (sldTime.getValue()/ audioInputStream.getFormat().getSampleRate());
    	                playMinutes = playTotalSecs/60;
    	                playSeconds = playTotalSecs%60;
    	                //show "play progress" over "total time"
    	                sldTime.setBorder(BorderFactory.createTitledBorder(playMinutes+":"+playSeconds+" / "+soundMinutes+":"+soundSeconds));
    	        	}
    	        }
    	    }
    	});
    	
    	sldTime.addMouseListener(new MouseAdapter() {
    		@Override
            public void mousePressed(MouseEvent e) {
    			if (myClip != null){
	            	Point p = e.getPoint();
	            	double percent = p.x / ((double) sldTime.getWidth());
	            	int range = sldTime.getMaximum() - sldTime.getMinimum();
	            	double newVal = range * percent;
	            	int result = (int)(sldTime.getMinimum() + newVal);
	            	sldTime.setValue(result);
	            	myClip.setFramePosition(sldTime.getValue());
	            	
	            	//get the progress of the player (playTotalSecs : in the foramt of seconds; playMinutes and playSeconds means "M:S")
	            	playTotalSecs = (int) (myClip.getFramePosition()/audioInputStream.getFrameLength() * totalSeconds);
	            	playMinutes = playTotalSecs/60;
	            	playSeconds = playTotalSecs%60;
	            	//show "play progress" over "total time"
	                sldTime.setBorder(BorderFactory.createTitledBorder(playMinutes+":"+playSeconds+" / "+soundMinutes+":"+soundSeconds));
	    		}
    		}
        });
    	
    	//the control of volume
    	/*adjust the jslide to control the volume, max = initial settings, min = max - 40db*/
    	sldVolume = new JSlider(0,100,0);
        sldVolume.setMajorTickSpacing(10);
        sldVolume.setMinorTickSpacing(5);
        //sldVolume.setPaintLabels(true);
        sldVolume.setPaintTicks(true);
        
    	sldVolume.setBorder(BorderFactory.createTitledBorder("volume"));
    	sldVolume.setMaximum(0);	//set maximum
    	sldVolume.setMinimum(-40);	//set minimum
    	sldVolume.addChangeListener(new ChangeListener(){
    	    public void stateChanged(ChangeEvent e)
    	    {
    	    	gainControl.setValue((float)sldVolume.getValue()) ;
    	    }
    	});
    	
    	sldVolume.addMouseListener(new MouseAdapter() {
    		@Override
            public void mousePressed(MouseEvent e) {
            	Point p = e.getPoint();
            	double percent = p.x / ((double) sldVolume.getWidth());
            	int range = sldVolume.getMaximum() - sldVolume.getMinimum();
            	double newVal = range * percent;
            	int result = (int)(sldVolume.getMinimum() + newVal);
            	sldVolume.setValue(result);
            	gainControl.setValue((float)sldVolume.getValue()) ;
            }
        });
    	
    	
        list = new PlayList();
        list.listFrame.setVisible(false);
    	
        f = new JFrame("Sound Player");
        f.setLayout(new BorderLayout());
        flg = new FileDialog(f, "Open media file", FileDialog.LOAD);

      
        p =  new JPanel(new FlowLayout());
        p_front = new JPanel();
        l_front = new JLabel();
        //l_front.setBackground();
        image = Toolkit.getDefaultToolkit().getImage("image/w_inf_01.png " );
        Icon icon = new ImageIcon(image);
        l_front.setIcon(icon);
        p.add(l_front);
        // TODO Auto-generated catch block
        p_front.setLayout(new FlowLayout());
        l_front.setLayout(new GridLayout());
        //f.getContentPane().add(p_front);
        
        buttonPlay = new JButton();
        buttonPause = new JButton();
        buttonStop = new JButton();
        buttonCircle = new JButton();
        buttonOpen = new JButton();
        buttonPL = new JButton();
        
        buttonPlay.setIcon(play_normal);
        buttonPause.setIcon(suspend_normal);
        buttonStop.setIcon(stop_normal);
        buttonCircle.setIcon(loopoff_normal);
        buttonOpen.setIcon(open_normal);
        buttonPL.setIcon(play_list);
        
        buttonPlay.setActionCommand("buttonPlay");
        buttonPause.setActionCommand("buttonPause");
        buttonStop.setActionCommand("buttonStop");
        buttonCircle.setActionCommand("buttonCircle");
        buttonOpen.setActionCommand("buttonOpen");
        buttonPL.setActionCommand("buttonPL");
        
        buttonPlay.addActionListener(this);
        buttonPause.addActionListener(this);
        buttonCircle.addActionListener(this);
        buttonStop.addActionListener(this);
        buttonOpen.addActionListener(this);
        buttonPL.addActionListener(this);
        
        buttonPlay.setSize(25,13);
        buttonPause.setSize(25,13);
        buttonCircle.setSize(25,13);
        buttonStop.setSize(25,13);
        buttonOpen.setSize(25,13);
        buttonPL.setSize(25,13);
        
        buttonPlay.setEnabled(false);
        buttonPause.setEnabled(false);
        buttonPause.setVisible(false);
        buttonStop.setEnabled(false);
        buttonCircle.setEnabled(false);
        buttonOpen.setEnabled(true);
        buttonPL.setEnabled(true);        

        buttonPlay.setOpaque( false );
        buttonPause.setOpaque( false );
        buttonPause.setOpaque( false );
        buttonStop.setOpaque( false );;
        buttonCircle.setOpaque( false );
        buttonOpen.setOpaque( false );
        buttonPL.setOpaque(false);
        
        buttonPlay.setContentAreaFilled( false );
        buttonPause.setContentAreaFilled( false );
        buttonPause.setContentAreaFilled( false );
        buttonStop.setContentAreaFilled( false );;
        buttonCircle.setContentAreaFilled( false );
        buttonOpen.setContentAreaFilled( false );
        buttonPL.setContentAreaFilled( false );
        p.setOpaque(false);
        p_front.setOpaque(false);
        p_front.add(buttonPlay);
        p_front.add(buttonPause,BorderLayout.SOUTH);
        p_front.add(buttonStop,BorderLayout.SOUTH);
        p_front.add(buttonCircle,BorderLayout.SOUTH);
        p_front.add(buttonOpen,BorderLayout.SOUTH);
        p_front.add(buttonPL,BorderLayout.SOUTH);
        buttonPlay.setPreferredSize(new java.awt.Dimension(25, 13));
        buttonPause.setPreferredSize(new java.awt.Dimension(25, 13));
        buttonCircle.setPreferredSize(new java.awt.Dimension(25, 13));
        buttonStop.setPreferredSize(new java.awt.Dimension(25, 13));
        buttonOpen.setPreferredSize(new java.awt.Dimension(25, 13));
        buttonPL.setPreferredSize(new java.awt.Dimension(25, 13));        
        
        
        sldTime.setOpaque(false);
        //sldTime.setBounds(66, 5, 120, 20);
        //p.setSize(300,25);
        //ImagePane G = new  ImagePane();
        //f.getContentPane().add(p); 

        //f.setSize( 320 ,  120 );
        l_front.add(sldTime);
        l_front.add(p_front);
        f.add(p, BorderLayout.SOUTH);
        sldTime.setPreferredSize(new java.awt.Dimension(120, 20));
        
        //G.add(sldVolume, BorderLayout.CENTER);
        f.pack();
        //f.setUndecorated(true);     
        f.setVisible(true);
        //l_front.setVisible(true);
        f.setResizable(false);//set resizability false
        f.setSize(320,120);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    

    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO Auto-generated method stub
        String cmd = e.getActionCommand();
        
        long tmp_fileLength = 0;
        float tmp_lengthPerSecond=0;
        int tmp_totalSeconds = 0;
        int tmp_soundMinutes = 0;
        int tmp_soundSeconds = 0;

        int id = -1;
        for (int i = 0; i <strCmd.length; i++)
            if(strCmd[i] == cmd) id=i;
        switch (id) {
            case Option.PLAY:
            	
            	myClipLoad();
                //myClip.start();
            	if(myClipSwith){
            		myClip.start();buttonCircle.setIcon(loopoff_normal);
            	}
            	else {
            		myClip.loop(-1);buttonCircle.setIcon(loopon_normal);
            	}
            	
                new Timer(1, new ActionListener(){
 
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                    	// TODO Auto-generated method stub
                    	if(myClip!=null){
	                        sldTime.setMaximum((int) audioInputStream.getFrameLength());
	                        sldTime.setValue(myClip.getFramePosition());
	                        
	                        
	                        if(sldTime.getValue() == (int) audioInputStream.getFrameLength()){
	                        	sldTime.setValue(0);
	                        	myClip.setFramePosition(0);
	                        	
	                        	//in the circle mode, maintain now status
	                        	if(!myClipSwith){
	                                buttonPlay.setEnabled(false);
	                                buttonPlay.setVisible(false);
	                                buttonPause.setEnabled(true);
	                                buttonPause.setVisible(true);                        		
	                        	}
                             //not in the circle mode: change states, reload the file, and end the clip
	                        	else{
	                            	buttonPlay.setEnabled(true);
	                            	buttonPlay.setVisible(true);
	                                buttonPause.setEnabled(false);
	                                buttonPause.setVisible(false);
	                                AudioLoad();
	                                myClip.close();
	                                myClip = null;
	                            }
	                        }
	                        
	                        //get the progress of the player (playTotalSecs : in the foramt of seconds; playMinutes and playSeconds means "M:S")
	    	        		    playTotalSecs = (int) (sldTime.getValue()/ audioInputStream.getFormat().getSampleRate());
	    	                playMinutes = playTotalSecs/60;
	    	                playSeconds = playTotalSecs%60;
	    	                //show "play progress" over "total time"
	    	                sldTime.setBorder(BorderFactory.createTitledBorder(playMinutes+":"+playSeconds+" / "+soundMinutes+":"+soundSeconds));
	                    }
                    }}).start();
                
                buttonPlay.setEnabled(false);
                buttonPlay.setVisible(false);
                buttonPause.setEnabled(true);
                buttonPause.setVisible(true);
                buttonStop.setEnabled(true);
                break;
            case Option.PAUSE:
                myClip.stop();
                buttonPlay.setEnabled(true);
                buttonPlay.setVisible(true);
                buttonPause.setEnabled(false);
                buttonPause.setVisible(false);
                //buttonCircle.setEnabled(true);
                break;
            case Option.STOP:
                AudioLoad();
                myClip.close();
                myClip = null;
                buttonPlay.setEnabled(true);
                buttonPlay.setVisible(true);
                buttonPause.setEnabled(false);
                buttonPause.setVisible(false);
                buttonStop.setEnabled(false);
                buttonCircle.setEnabled(true);
                break;
            case Option.CIRCLE:
            	myClipLoad();
            	//myClipSwih - the boolean control variable of the circle mode of player
            	if(myClipSwith){
            		myClip.start();buttonCircle.setIcon(loopoff_normal);
            		myClipSwith=false;
            		}
            	else {
            		myClip.loop(-1);buttonCircle.setIcon(loopon_normal);
            		myClipSwith=true;
            		}
                new Timer(1, new ActionListener(){
                	 
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                    	// TODO Auto-generated method stub
                    	if(myClip != null){
	                        sldTime.setMaximum((int) audioInputStream.getFrameLength());
	                        sldTime.setValue(myClip.getFramePosition());
	                        if(sldTime.getValue() == (int) audioInputStream.getFrameLength()){
	                        	sldTime.setValue(0);
	                        	myClip.setFramePosition(0);
	                        	
	                        	//in the circle mode, maintain now status
	                        	if(!myClipSwith){
	                                buttonPlay.setEnabled(false);
	                                buttonPlay.setVisible(false);
	                                buttonPause.setEnabled(true);
	                                buttonPause.setVisible(true);
	                        		
	                        	}
	                        	//not in the circle mode: change states, reload the file, and end the clip
	                        	else{
	                            	buttonPlay.setEnabled(true);
	                            	buttonPlay.setVisible(true);
	                                buttonPause.setEnabled(false);
	                                buttonPause.setVisible(false);
	                                AudioLoad();
	                                myClip.close();
	                                myClip = null;
	                            }
	                        }
	                        
	                       //get the progress of the player (playTotalSecs : in the foramt of seconds; playMinutes and playSeconds means "M:S")
	     	        		    playTotalSecs = (int) (sldTime.getValue()/ audioInputStream.getFormat().getSampleRate());
	     	                playMinutes = playTotalSecs/60;
	     	                playSeconds = playTotalSecs%60;
	     	                //show "play progress" over "total time"
	     	                sldTime.setBorder(BorderFactory.createTitledBorder(playMinutes+":"+playSeconds+" / "+soundMinutes+":"+soundSeconds));
	                    }
                    }}).start();
                
                buttonPlay.setEnabled(false);
                buttonPlay.setVisible(false);
                buttonPause.setEnabled(true);
                buttonPause.setVisible(true);
                buttonStop.setEnabled(true);
                //buttonCircle.setEnabled(false);
                break;
            case Option.OPEN:
            	flg.setVisible(true);
                if(!flg.getFile().equals("null")){
                    pathNum++;//add path number
                    pathCurrent = pathNum-1;// set the path pointer to the last place
                    
                    AudioLoad();
                    
        	        tmp_fileLength = audioInputStream.getFrameLength();
        	        tmp_lengthPerSecond = audioInputStream.getFormat().getSampleRate();
        	        tmp_totalSeconds = (int) (tmp_fileLength/tmp_lengthPerSecond);
        	        tmp_soundMinutes = tmp_totalSeconds/60;
        	        tmp_soundSeconds = tmp_totalSeconds%60;
                    
                	list.listAdd(pathCurrent,pathNum, flg.getFile(), flg.getDirectory(), tmp_soundMinutes+":"+tmp_soundSeconds);
                    list.pathCurrent = pathCurrent;
                    list.pathNum = pathNum;
                	buttonPlay.setEnabled(true);
                    buttonPlay.setVisible(true);
                    buttonPause.setEnabled(false);
                    buttonPause.setVisible(false);
                    buttonStop.setEnabled(false);
                    buttonCircle.setEnabled(true);
                    
                }
                break;
            case Option.LIST:
            	list.listFrame.setVisible(true);
            	break;
            default:
        }
             
         
    }
}